package com.flong.controller;

import java.util.Date;
import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import com.flong.dao.IUserDao;
import com.flong.entity.User;
import com.flong.service.IRedisService;
import com.flong.service.IUserService;
import com.flong.utils.DateUtil;
import com.flong.utils.ObjectUtil;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;

@Controller
@SuppressWarnings("all")
@Api("用户模块API")
public class UserController {
	
	private final String USER_REDIS_KEY = "QUERY_USER_LIST_REDIS_KEY"; 
	private final String USER_REDIS_BACKUP_KEY = "USER_REDIS_BACKUP_KEY"; 
	private final static Logger logger = LoggerFactory.getLogger(UserController.class);
	@Autowired private IUserService userService;
	@Autowired private IRedisService redisService;
	@Autowired private IUserDao userMapper;
	
	//创建公平锁
	private Lock rock = new ReentrantLock(true);
	
	
	
	@ResponseBody
	@RequestMapping("/delById")
	public String delById(Integer id) {
	 
		//userMapper.deleteById(id);
		logger.info("删除成功！");
		return "Success";
	}
	
	
	

	@ApiOperation(value="查询用户信息",notes="获取用户信息")
	@ApiImplicitParams({
         @ApiImplicitParam(paramType="header",name="id",dataType="String",required=true,value="用户Id",defaultValue="1")
	})
    @ApiResponses({
        @ApiResponse(code=400,message="请求参数没填好"),
        @ApiResponse(code=404,message="请求路径没有或页面跳转路径不对")
    })
	@ResponseBody
	@RequestMapping("/queryUserInfo")
	public List<User> queryUserInfo(Integer id) {
		
		//1-->测试不使用缓存的查询
		//return nonUseRedis(id);
		
		//2-->测试使用redis缓存,但没线程synchronized重量级锁)安全的并发查询
		//return nonUseThreadButRedis(id);
	
		//3-->使用rock并发和redis进行处理缓存
	   return nonUseRockButRedis(id);
	   
	}

	/**
	 * @Description 没使用线程安全查询，但是使用了redis缓存,1000个并发的时候运行一段时间之后还是会挂好几个，虽然减少部分错误.
	 *              在方法加了synchronized虽然能解决部分的并发请求，但是超过1000以上一直卡死不动.完全死锁不释放.
	 * @Author		liangjl
	 * @Date		2018年2月3日 下午2:46:14
	 * @param id
	 * @return 参数
	 * @return List<User> 返回类型 
	 * @throws
	 */
	private  List<User> nonUseRockButRedis(Integer id) {
		List<User> retDataList = null;
		rock.lock();
		//如果请求拿到cup分配的线程锁就往下走.
		if(rock.tryLock()) {
			try {
				Date startDate = new Date() ;//开始时间
				String startDateStr  = DateUtil.formatDate(startDate, "yyyy-MM-dd HH:mm:ss");
				//从缓存获取数据
				retDataList = (List<User>)redisService.get(USER_REDIS_KEY+"_"+id);
				
				//判断缓存是否等于空
				if(ObjectUtil.isEmpty(retDataList)) {
					//查数据库
					retDataList = userService.getUserList(id);
					Date endDate = new Date() ;//结束时间
					redisService.set(USER_REDIS_KEY+"_"+id, retDataList,20L);
					
					//如果数据库的值为空就把它设置一个过期时间
					if(ObjectUtil.isEmpty(retDataList)) {
						redisService.set(USER_REDIS_KEY+"_"+id, retDataList,20L);
					}else {
						//放入备份缓存
						redisService.set(USER_REDIS_BACKUP_KEY+"_"+id, retDataList,20L);
					}
					String endDateStr= DateUtil.formatDate(endDate, "yyyy-MM-dd HH:mm:ss");
					logger.info("数据库-->执行情况-->>【开始时间为："+startDateStr+"\t,结束时间为："+endDateStr+
							"\t,执行秒数："+DateUtil.getBetweeDay(endDate, startDate)+"】");
					
					return retDataList;
				}else {
					Date endDate = new Date() ;//结束时间
					String endDateStr= DateUtil.formatDate(endDate, "yyyy-MM-dd HH:mm:ss");
					logger.info("缓存-->执行情况-->>【开始时间为："+startDateStr+"\t,结束时间为："+endDateStr+
							"\t,执行秒数："+DateUtil.getBetweeDay(endDate, startDate)+"】");
					
					return retDataList;
				}
			} catch (Exception e) {
				e.printStackTrace();
			}finally {
				//手动释放锁
				rock.unlock();
			}
		}else {
			//从备份缓存获取springboot初始化.
			retDataList = (List<User>)redisService.get(USER_REDIS_BACKUP_KEY+"_"+id);
		}

		return retDataList;
	}
	
	
	
	/**
	 * @Description 没使用线程安全查询，但是使用了redis缓存,1000个并发的时候运行一段时间之后还是会挂好几个，虽然减少部分错误.
	 *              在方法加了synchronized虽然能解决部分的并发请求，但是超过1000以上一直卡死不动.完全死锁不释放.
	 * @Author		liangjl
	 * @Date		2018年2月3日 下午2:46:14
	 * @param id
	 * @return 参数
	 * @return List<User> 返回类型 
	 * @throws
	 */
	private /*synchronized*/ List<User> nonUseThreadButRedis(Integer id) {
		Date startDate = new Date() ;//开始时间

		String startDateStr  = DateUtil.formatDate(startDate, "yyyy-MM-dd HH:mm:ss");
		//从缓存获取数据
		List<User> retDataList = (List<User>)redisService.get(USER_REDIS_KEY+"_"+id);
		
		//判断缓存是否等于空
		if(ObjectUtil.isEmpty(retDataList)) {
			//查数据库
			retDataList = userService.getUserList(id);
			Date endDate = new Date() ;//结束时间
			redisService.set(USER_REDIS_KEY+"_"+id, retDataList,20L);
			
			//如果数据库的值为空就把它设置一个过期时间
			if(ObjectUtil.isEmpty(retDataList)) {
				redisService.setExpire(USER_REDIS_KEY+"_"+id, 300L);
			}
			
			String endDateStr= DateUtil.formatDate(endDate, "yyyy-MM-dd HH:mm:ss");
			logger.info("数据库-->执行情况-->>【开始时间为："+startDateStr+"\t,结束时间为："+endDateStr+
					"\t,执行秒数："+DateUtil.getBetweeDay(endDate, startDate)+"】");
			
			return retDataList;
		}else {
			
			Date endDate = new Date() ;//结束时间
			String endDateStr= DateUtil.formatDate(endDate, "yyyy-MM-dd HH:mm:ss");
			logger.info("缓存-->执行情况-->>【开始时间为："+startDateStr+"\t,结束时间为："+endDateStr+
					"\t,执行秒数："+DateUtil.getBetweeDay(endDate, startDate)+"】");
			
			return retDataList;
		}
	}



	/**
	 * @Description 不使用缓存的查询,通过jmeter测试,1000个并发,直接挂很多请求
	 * @Author		liangjl
	 * @Date		2018年2月3日 下午2:34:43
	 * @param id
	 * @return 参数
	 * @return List<User> 返回类型 
	 * @throws
	 */
	private List<User> nonUseRedis(Integer id) {
		
		Date startDate = new Date() ;//开始时间

		String startDateStr  = DateUtil.formatDate(startDate, "yyyy-MM-dd HH:mm:ss");
		List<User> userList = userService.getUserList(id);
		
		Date endDate = new Date() ;//结束时间
		String endDateStr= DateUtil.formatDate(endDate, "yyyy-MM-dd HH:mm:ss");
		
		logger.info("数据库-->执行情况-->>【开始时间为："+startDateStr+"\t,结束时间为："+endDateStr+
				"\t,执行秒数："+DateUtil.getBetweeDay(endDate, startDate)+"】");
		return userList;
	}
	
	
	
	@RequestMapping("/index")
	public ModelAndView index(String param) {
		return new ModelAndView("index");
	}
	
	
}